package com.jollychic.db.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.jollychic.db.annotation.Column;
import com.jollychic.utils.ReflectUtils;
import com.jollychic.utils.StringUtils;
import com.jollychic.utils.YamlUtils;
import com.jollychic.db.DBConfig;
import com.jollychic.db.DBEnum;

/**
 * DB 工具类
 */
public final class DBUtils {

	private static DBConfig config = null;

	static {
		config = YamlUtils.interpretYaml(new DBConfig() {
			@Override
			public DBConfig interpretYaml(Map map) {
				/****** 解析规则 ******/
				Map mysql = (Map) map.get(DBEnum.MYSQL.getS());
				String d = String.valueOf(mysql.get(DBEnum.DRIVER.getS()));
				String u = String.valueOf(mysql.get(DBEnum.URL.getS()));
				String s = String.valueOf(mysql.get(DBEnum.USER.getS()));
				String p = String.valueOf(mysql.get(DBEnum.PASSWORD.getS()));
				setConf(d, u, s, p);
				return this;
			}
		});
	}

	/**
	 * 提取 数据连接
	 * 
	 * @return
	 */
	public static Connection getCon() {
		Connection con = null;
		try {
			Class.forName(config.DIRVER);
			con = DriverManager.getConnection(config.URL, config.USER, config.PASSWORD);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return con;
	}

	/**
	 * 获取ps对象
	 * 
	 * @param sqlStr
	 * @return
	 */
	public static PreparedStatement getPS(String sqlStr) {
		Connection con = getCon();
		PreparedStatement ps = null;
		if (con != null) {
			try {
				ps = con.prepareStatement(sqlStr);
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException(" create prepareStatement is fail");
			}
		} else {
			throw new RuntimeException("DB connection is null");
		}
		return ps;
	}

	/**
	 * PreparedStatement 设置参数
	 * 
	 * @param ps
	 * @param params
	 */
	public static PreparedStatement setParams(PreparedStatement ps, Object[] params) {
		// 设置参数
		if (StringUtils.isNotEmpty(params)) {
			for (int i = 0; i < params.length; i++) {
				try {
					ps.setObject(i + 1, params[i]);
				} catch (SQLException e) {
					e.printStackTrace();
					throw new RuntimeException("set sql params has a error");
				}
			}
		}
		return ps;
	}

	/**
	 * 查询单个对象
	 */
	public static <T> T getRSet2One(ResultSet rs, Class<T> c) {
		T t = ReflectUtils.getObj(c);
		// 提取属性名称
		Field[] fields = ReflectUtils.getFields(c);
		try {
			while (rs.next()) {
				setField(rs, fields, t);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return t;

	}

	/**
	 * 查询多个对象
	 */
	public static <T> List<T> getRSet2List(ResultSet rs, Class<T> c) {
		// 提取属性名称
		Field[] fields = ReflectUtils.getFields(c);
		List<T> lst = new ArrayList<>();
		try {
			while (rs.next()) {
				T t = ReflectUtils.getObj(c);
				setField(rs, fields, t);
				lst.add(t);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return lst;

	}

	/**
	 * 设置对象属性值
	 * 
	 * @param rs
	 * @param c
	 * @param fields
	 * @param t
	 * @throws Exception
	 */
	private static <T> void setField(ResultSet rs, Field[] fields, T t) throws Exception {
		for (Field f : fields) {
			String fildName = f.getName();
			String columnName = fildName;
			Column column = f.getAnnotation(Column.class);
			if (column != null) {
				columnName = column.Column();
			}
			// 提取db值
			Object v = rs.getObject(columnName);
			Method method = ReflectUtils.getMethod(t.getClass(), "set" + StringUtils.captureName(fildName),
					f.getType());
			method.invoke(t, v);
		}
	}

	/**
	 * 流的关闭
	 * 
	 * @param con 连接
	 * @param ps  PreparedStatement
	 * @param rs  ResultSet
	 */
	public static void close(Connection con, PreparedStatement ps, ResultSet rs) {
		try {
			if (rs != null) {
				rs.close();
			}
			if (ps != null) {
				ps.close();
			}
			if (con != null) {
				con.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	public static void close(PreparedStatement ps, ResultSet rs) {
		try {
			if (rs != null) {
				rs.close();
			}
			if (ps != null) {
				ps.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public static void close(Connection con) {
		try {
			if (con != null) {
				con.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	public static void close(PreparedStatement ps) {
		try {
			if (ps != null) {
				ps.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public static void close(ResultSet rs) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

}
